﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SearchBackEnd
{
    class PageDatabase
    {

        private Dictionary<Page, PageData> pages = new Dictionary<Page, PageData>(new PageComparer());
        private SearchIndex searchIndex = new SearchIndex();
        private long primaryPageCount = 0;
        private long secondaryPageCount = 0;

        /// <summary>
        /// Search the primary pages in the database for a set of keywords.
        /// </summary>
        /// <param name="keyWords"></param>
        /// <returns></returns>
        public String[] Search(String[] keyWords)
        {
            return searchIndex.SearchPage(keyWords);
        }

        /// <summary>
        /// Removes a page from the database.
        /// </summary>
        /// <param name="page"></param>
        public void RemovePage(Page page)
        {
            Boolean isPrimary = searchIndex.RemovePageFromIndex(page);
            Boolean isFound = pages.Remove(page);
            if (isFound)
            {
                if (isPrimary) primaryPageCount--;
                else secondaryPageCount--;
            }
        }

        /// <summary>
        /// adds a page to the db and indices it if it the primary copy.
        /// </summary>
        /// <param name="page">the page to index</param>
        /// <param name="isPrimary">is this the primary copy of the page.</param>
        /// <param name="other">the other server that hold this page.</param>
        public void AddPage(Page page, Boolean isPrimary, String other)
        {

            if (isPrimary)
            {
                searchIndex.AddToIndex(page); //index page
                primaryPageCount++;
            }
            else
            {
                secondaryPageCount++;
            }
            pages.Add(page, new PageData(other, isPrimary));
        }

        /// <summary>
        /// Return all primary/secondary pages and the address of the server that holds the second copy.
        /// </summary>
        /// <param name="isPrimary"></param>
        /// <returns></returns>
        public Dictionary<Page, String> GetAllPages(Boolean isPrimary)
        {
            Dictionary<Page, String> res = new Dictionary<Page, String>();
            Dictionary<Page, PageData>.Enumerator iter = pages.GetEnumerator();
            while (iter.MoveNext())
            {
                if (iter.Current.Value.IsPrimary == isPrimary)
                {
                    res.Add(iter.Current.Key, iter.Current.Value.Other);
                }
            }
            return res;
        }

        /// <summary>
        /// Get all the pages that their other primary/secondary copy is held by a specific server. 
        /// </summary>
        /// <param name="other"></param>
        /// <param name="isOtherPrimary"></param>
        /// <returns></returns>
        public Page[] GetPages(String other, Boolean isOtherPrimary)
        {
            List<Page> res = new List<Page>();
            foreach (Page p in pages.Keys)
            {
                PageData currData = pages[p];
                if (currData.Other.Equals(other) && currData.IsPrimary != isOtherPrimary)
                    res.Add(p);
            }
            return res.ToArray();
        }

        /// <summary>
        /// update the address of the server that hold the other copy of a specific page.
        /// </summary>
        /// <param name="page"></param>
        /// <param name="other"></param>
        public void UpdatePageOther(Page page, String other)
        {
            pages[page].Other = other;
        }

        /// <summary>
        /// get the number of primary/secondary pages.
        /// </summary>
        /// <param name="isPrimary"></param>
        /// <returns></returns>
        public long GetPageCount(Boolean isPrimary)
        {

            return isPrimary ? primaryPageCount : secondaryPageCount;
        }

        /// <summary>
        /// meta data of a page in the page database.
        /// </summary>
        class PageData
        {
            public PageData(String other, Boolean isPrimary)
            {
                this.Other = other;
                this.IsPrimary = isPrimary;
            }
            public String Other { get; set; }
            public Boolean IsPrimary { get; set; }
        }

        public Boolean IsPageExists(Page p)
        {
            return pages.ContainsKey(p);
        }
    }

    /// <summary>
    /// comparator that compares pages by their name.
    /// </summary>
    class PageComparer : IEqualityComparer<Page>
    {

        public bool Equals(Page p1, Page p2)
        {
            return p1.Name.Equals(p2.Name);
        }


        public int GetHashCode(Page p)
        {
            return p.Name.GetHashCode();
        }
    }
}
